package com.sinodata.bsm.center.service.resource;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.sinodata.bsm.center.bean.ResBean;
import com.sinodata.bsm.center.cache.CollectFieldCache;
import com.sinodata.bsm.center.cache.CollectParamCache;
import com.sinodata.bsm.center.cache.CollectScheduleCache;
import com.sinodata.bsm.center.cache.CollectTaskCache;
import com.sinodata.bsm.center.cache.CollectorCache;
import com.sinodata.bsm.center.cache.PropertyCache;
import com.sinodata.bsm.center.cache.PropertyDisplayCache;
import com.sinodata.bsm.center.dao.BaseDao;
import com.sinodata.bsm.center.message.ProbeMessenger;
import com.sinodata.bsm.center.util.spring.SpringContextHolder;
import com.sinodata.bsm.common.vo.CollectField;
import com.sinodata.bsm.common.vo.CollectParam;
import com.sinodata.bsm.common.vo.CollectSchedule;
import com.sinodata.bsm.common.vo.CollectScheduleInmp;
import com.sinodata.bsm.common.vo.CollectTask;
import com.sinodata.bsm.common.vo.Collector;
import com.sinodata.bsm.common.vo.Property;
import com.sinodata.bsm.common.vo.PropertyDisplay;

@Service
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public class CollectTaskService {
    @Autowired
    private BaseDao baseDao;

    @Autowired
    private CollectTaskCache collectTaskCache;
    @Autowired
    private CollectParamCache collectParamCache;
    @Autowired
    private CollectFieldCache collectFieldCache;
    @Autowired
    private PropertyDisplayCache propertyDisplayCache;
    @Autowired
    private CollectScheduleCache collectScheduleCache;
    @Autowired
    private CollectorCache collectorCache;

    public CollectTask getById(Long taskId) {
        return collectTaskCache.get(taskId);
    }

    public List<CollectTask> findByResTypeId(Long resTypeId) {

        return collectTaskCache.getByResTypeId(resTypeId);
    }

    public List<CollectTask> findByChildResTypeId(Long childResTypeId) {
        return collectTaskCache.findByChildResTypeId(childResTypeId);
    }

    public List<CollectParam> getCollectParam(Long taskId) {
        return collectParamCache.get(taskId);
    }

    public List<CollectField> getCollectField(Long taskId) {
        return collectFieldCache.get(taskId);
    }

    public List<CollectSchedule> getCollectSchedule(Long taskId) {
        return collectScheduleCache.get(taskId);
    }

    public Collector getCollector(Long id) {
        return collectorCache.get(id);
    }

    /**
     * 获取一个资源的采集调度规则
     * @param resId
     * @return
     */
    public List<CollectTask> findByResId(Long resId) {
        return collectTaskCache.getByResId(resId);

    }

    /**
     * 获取一个资源的所有父资源类别上定义的采集规则
     * @param resId
     * @return
     */
    public List<CollectTask> findFatherTaskByResId(Long resId) {
        List<CollectTask> parentTypelist = new ArrayList<CollectTask>();
        List<ResBean> parentResBean = ResBean.get(resId).parents();
        if (parentResBean != null && parentResBean.size() > 0) {
            Set<Long> patenRresTypeIdSet = new HashSet<Long>();
            for (ResBean parent : parentResBean) {
                Long parentResTypeId = parent.res().getResTypeId();
                if (patenRresTypeIdSet.contains(parentResTypeId)) {
                    continue;
                }
                patenRresTypeIdSet.add(parentResTypeId);
                List<CollectTask> list = findByResTypeId(parentResTypeId);
                if (list != null && list.size() > 0) {
                    parentTypelist.addAll(list);
                }
            }
        }
        return parentTypelist;
    }

    /**
     * 
     * @param resId 准备要复制的资源Id
     * @param resIds 将要被批量复制的资源Id
     * @throws Exception 
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void batchSaveCollectTask(Long resId, Long[] resIds) throws Exception {
        List<CollectTask> fromList = findByResId(resId);
        if (fromList == null || fromList.size() == 0) {
            return;
        }
        List<CollectTask> fromList2 = new ArrayList<CollectTask>();
        for (int i = 0; i < fromList.size(); i++) {
            CollectTask t = fromList.get(i);
            //检查是否是源id的自定义指标的采集规则。
            if (!isResCollectTask(t.getId())) {
                fromList2.add(t);
            }
        }
        for (Long toResId : resIds) {
            cloneCollectTask(fromList2, toResId);
        }
    }

    /**
     * 判断是否是资源采集器
     * @param taskId
     * @return
     */
    private boolean isResCollectTask(Long taskId) {
        boolean hasCustomize = false;
        List<CollectField> fieldList = collectFieldCache.get(taskId.longValue());
        for (int j = 0; fieldList != null && j < fieldList.size(); j++) {
            CollectField f = fieldList.get(j);
            Property prop = SpringContextHolder.getBean(PropertyCache.class).get(f.getProp().longValue());
            if (prop != null && prop.getResId() != null) {
                hasCustomize = true;
                break;
            }
        }
        return hasCustomize;
    }

    /**
     * 
     * @param cloneList
     * @param toResIds
     * @throws Exception
     */
    private void cloneCollectTask(List<CollectTask> cloneList, Long toResIds) throws Exception {
        /**
         * 保存前，先删除旧规则
         */
        List<CollectTask> oldTasks = findByResId(toResIds);
        if (oldTasks != null) {
            for (int i = oldTasks.size() - 1; i >= 0; i--) {
                if (isResCollectTask(oldTasks.get(i).getId())) {
                    //不删除自定义指标
                    continue;
                }
                deleteCollectTask(oldTasks.get(i).getId());
            }
        }
        for (int i = 0; cloneList != null && i < cloneList.size(); i++) {
            CollectTask task = cloneList.get(i).clone();
            task.setId(null);
            task.setResId(toResIds);
            List<CollectSchedule> fromScheduleList = getCollectSchedule(cloneList.get(i).getId());
            List<CollectSchedule> toScheduleList = new ArrayList<CollectSchedule>();
            for (int j = 0; fromScheduleList != null && j < fromScheduleList.size(); j++) {
                CollectSchedule schedule = fromScheduleList.get(j).clone();
                schedule.setId(null);
                schedule.setCollectTaskId(task.getId());
                toScheduleList.add(schedule);
            }
            List<CollectParam> fromParamList = getCollectParam(cloneList.get(i).getId());
            List<CollectParam> toParamList = new ArrayList<CollectParam>();
            for (int j = 0; fromParamList != null && j < fromParamList.size(); j++) {
                CollectParam param = fromParamList.get(j).clone();
                param.setId(null);
                param.setCollectTaskId(task.getId());
                toParamList.add(param);
            }
            List<CollectField> fromFieldList = getCollectField(cloneList.get(i).getId());
            List<CollectField> toFieldList = new ArrayList<CollectField>();
            for (int j = 0; fromFieldList != null && j < fromFieldList.size(); j++) {
                CollectField field = fromFieldList.get(j).clone();
                field.setId(null);
                field.setCollectTaskId(task.getId());
                toFieldList.add(field);
            }
            saveOrUpdateCollectTask(task, toScheduleList, toParamList, toFieldList);
        }

    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void updateCollectTask(CollectTask task) throws Exception {
        if (task.getResId() == null) {
            throw new Exception();
        }
        baseDao.update(task);
        collectTaskCache.put(task.getId(), task);
    }

    /**
     * 新增或修改一个采集调度任务
     * @param task
     * @param scheduleList
     * @param paramList
     * @param fieldList
     * @throws Exception
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void saveOrUpdateCollectTask(CollectTask task, List<CollectSchedule> scheduleList, List<CollectParam> paramList, List<CollectField> fieldList) throws Exception {
        if (task.getResId() == null) {
            throw new Exception();
        }
        baseDao.saveOrUpdate(task);
        collectTaskCache.put(task.getId(), task);
        for (CollectField field : fieldList) {
            field.setCollectTaskId(task.getId());
            baseDao.saveOrUpdate(field);
        }
        collectFieldCache.removeByCollectTaskId(task.getId());
        collectFieldCache.put(task.getId(), fieldList);
        for (CollectParam param : paramList) {
            param.setCollectTaskId(task.getId());
            baseDao.saveOrUpdate(param);
        }
        collectParamCache.removeByCollectTaskId(task.getId());
        collectParamCache.put(task.getId(), paramList);
        for (CollectSchedule schedule : scheduleList) {
            schedule.setCollectTaskId(task.getId());
            baseDao.saveOrUpdate(schedule);
            collectScheduleCache.put(schedule);
        }
        collectScheduleCache.removeByCollectTaskId(task.getId());
        collectScheduleCache.put(task.getId(), scheduleList);
        ProbeMessenger.notifyCollectAddOrUpdate(task, scheduleList, paramList, fieldList);
    }

    /**
     * 删除一个资源的所有自定义规则
     * @param collectTaskId
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void deleteCollectTaskByResId(Long resId) {
        List<CollectTask> taskList = findByResId(resId);
        if (taskList != null) {
            for (int i = taskList.size() - 1; i >= 0; i--) {
                deleteCollectTask(taskList.get(i).getId());
            }
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void deleteCollectTask(Long collectTaskId) {
        CollectTask task = collectTaskCache.get(collectTaskId);
        if (task.getResId() == null) {
            return;
        }
        ProbeMessenger.notifyCollectDelete(task.getResId(), collectTaskId);
        deleteCollectTaskConf(collectTaskId);
        collectTaskCache.remove(collectTaskId);
        baseDao.delete(task);

    }

    /**
     * 删除一个采集配置实例的配置的子表
     * 即删除一个采集配置实例下的所有 CollectField\CollectParam\CollectSchedule
     * @param collectTaskId
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void deleteCollectTaskConf(Long collectTaskId) {
        CollectTask task = collectTaskCache.get(collectTaskId);
        if (task.getResId() == null) {
            return;
        }
        List<CollectField> fieldList = collectFieldCache.get(collectTaskId);
        if (fieldList != null) {
            for (int i = fieldList.size() - 1; i >= 0; i--) {
                CollectField field = fieldList.get(i);
                collectFieldCache.remove(field.getId().longValue());
                baseDao.delete(field);

            }
        }
        List<CollectParam> paramList = collectParamCache.get(collectTaskId);
        if (paramList != null) {
            for (int i = paramList.size() - 1; i >= 0; i--) {
                CollectParam param = paramList.get(i);
                baseDao.delete(param);
                collectParamCache.remove(param.getId().longValue());

            }
        }
        List<CollectSchedule> scheduleList = collectScheduleCache.get(collectTaskId);
        if (scheduleList != null) {
            for (int i = scheduleList.size() - 1; i >= 0; i--) {
                CollectSchedule schedule = scheduleList.get(i);
                baseDao.delete(schedule);
                collectScheduleCache.remove(schedule.getId().longValue());

            }
        }
    }

    /**
     * saveOrUpdateCollectTask的重写 将delete和save的事务进行统一管理
     * @param isDelete
     * @param task
     * @param scheduleList
     * @param paramList
     * @param fieldList
     * @throws Exception
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void saveOrUpdateCollectTask(Boolean isDelete, CollectTask task, List<CollectSchedule> scheduleList, List<CollectParam> paramList, List<CollectField> fieldList) throws Exception {
        if (isDelete == true) {
            this.deleteCollectTaskConf(task.getId());
        }
        this.saveOrUpdateCollectTask(task, scheduleList, paramList, fieldList);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public boolean saveOrUpdateNetconfig(CollectScheduleInmp entity) {
        baseDao.saveOrUpdate(entity);
        if (baseDao.findById(CollectScheduleInmp.class, entity.getId()) != null) {
            return true;
        }
        return false;
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void addCollectTask(CollectTask task) {
        baseDao.saveOrUpdate(task);
        collectTaskCache.put(task.getId(), task);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void addCollectParams(List<CollectParam> paramList) {
        for (CollectParam param : paramList) {
            baseDao.saveOrUpdate(param);
        }
        if (paramList.size() != 0) {
            collectParamCache.removeByCollectTaskId(paramList.get(0).getCollectTaskId());
            collectParamCache.put(paramList.get(0).getCollectTaskId(), paramList);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void addCollectField(CollectField collectField) {
        baseDao.saveOrUpdate(collectField);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void addPropertyDisplay(PropertyDisplay propertyDisplay) {
        baseDao.saveOrUpdate(propertyDisplay);
        propertyDisplayCache.put(propertyDisplay.getId(), propertyDisplay);
    }
}
